package com.pic.mgt.haishin.executer;

import java.sql.Timestamp;
import java.util.Date;

import org.springframework.dao.DataAccessException;

import com.pic.mgt.IgxStatus;
import com.pic.mgt.dao.haishin.HaishinBusinessMgtDao;
import com.pic.mgt.dao.haishin.IHaishinBusinessMgtDao;
import com.pic.mgt.executer.BusinessUnitExecuter;
import com.pic.mgt.executer.IGXTypeExecutionException;
import com.pic.mgt.executer.TargetAction;
import com.pic.mgt.log.IgxLog;
import com.pic.mgt.unit.operation.BusinessUnitOperation;
import com.pic.mgt.unit.operation.UnitOperationException;

public abstract class HaishinBusinessUnitExecuter extends BusinessUnitExecuter {
	private BusinessUnitOperation simpleBusinessUnitOperation;
	protected String haishinOutboxPathStr;
	
	protected TerminalListener terminalListener;
	
	private IHaishinBusinessMgtDao haishinBusinessMgtDao;
	
	public HaishinBusinessUnitExecuter(TargetAction targetAction,
						   TerminalListener terminalListener) {
		super(targetAction);
		
		this.terminalListener = terminalListener;
		
		// 設定目標檔案處理結果通知。
		useTargetFileProcessResultNotify();
	}
	
	/*
	 * 設定目標檔案處理完成通知。
	 * 設定此通知，目標檔處理過程，會針對每一個端末配信時，
	 * 觸發 terminalProcessNotify()方法通知。
	 */
	private void useTargetFileProcessResultNotify() {
		// 註冊目標檔處理通知
		HaishinTargetFileProcess targetFileProcess =
							(HaishinTargetFileProcess)this.targetAction;
		targetFileProcess.
			setTerminalListener(this.terminalListener);
	}
	
	@Override
	/**
	 * 覆寫掉super class(BusinessUnitExecuter) 的 updateStatusWhenBeginExecution()
	 * 方法。因為配信的執行前狀態更新，除了狀態更新外還要更新執行時間。
	 */
	protected void updateStatusWhenBeginExecution() throws DataAccessException {
		String status = null;
		// throws DataAccessException
		updateStatusAndExecutionTimeByUnitName(IgxStatus.BUSINESS_EXECUTING);
		
		// ********************** Log **********************
		if (IgxLog.messageLog.isTraceMode()) {
			IgxLog.messageLog.trace(this,
					"Update status and execution time to db table '{}' for unit '{}' completed.",
					super.businessMgtDao.getTableName() ,
					super.unit.getUnitName());
		}
		// ********************** Log **********************
	}
	
	@Override
	/**
	 *  覆寫掉super class(BusinessUnitExecuter) 的 updateStatusWhenExecutionSuccess()
	 *  方式。因為配信的成功執行後狀態更新，除了狀態更新外還要將 redo_asgin_terminal 和 
	 *  redo_asgin_terminal_files 更新(為null)
	 */
	protected void updateStatusWhenExecutionSuccess()
			throws DataAccessException {
		// throws DataAccessException
		updateStatusAndRedoAsginTerminalsByUnitName(IgxStatus.BUSINESS_COMPLETED,
										            null);
		
		// ********************** Log **********************
		if (IgxLog.messageLog.isTraceMode()) {
			IgxLog.messageLog.trace(this,
					"Update status and redo asgin terminals to db table '{}' for unit '{}' completed.",
					super.businessMgtDao.getTableName() ,
					super.unit.getUnitName());
		}
		// ********************** Log **********************
	}
	
	private void updateStatusAndExecutionTimeByUnitName(String statusValue)
												throws DataAccessException {
		if (null == this.haishinBusinessMgtDao) {
			this.haishinBusinessMgtDao = 
				(HaishinBusinessMgtDao)super.businessMgtDao;
		}
		
		try {
			// 取得現在時間的 Timestamp
			Timestamp currentTimestamp = new Timestamp(new Date().getTime());
			
			// throws DataAccessException
			this.haishinBusinessMgtDao.updateStatusAndExecutionTimeByUnitName(
								statusValue,
								currentTimestamp,
								super.unit.getUnitName());
		} catch (DataAccessException e) {
			// ********************** Log **********************
			IgxLog.messageDetailsLog.error(this, e.getMessage());
			// ********************** Log **********************
			
			// ********************** Log **********************
			IgxLog.messageLog
					.error(
							this,
							"Update status and execution time to db table '{}' for unit '{}' failed.",
							this.haishinBusinessMgtDao.getTableName(),
							super.unit.getUnitName());
			// ********************** Log **********************
			
			throw e;
		}
	}
	
	/**
	 * 更新 Status 和 RedoAsginTerminal 欄位,其中還會更新 RedoAsginTerminalFiles 欄位,
	 * RedoAsginTerminalFiles 欄位一律更新為空(null).
	 * @param statusValue
	 * @param redoAsginTerminals
	 * @throws DataAccessException
	 */
	private void updateStatusAndRedoAsginTerminalsByUnitName(String statusValue,
			String redoAsginTerminals) 
													throws DataAccessException {
		if (null == this.haishinBusinessMgtDao) {
			this.haishinBusinessMgtDao = 
				(HaishinBusinessMgtDao)super.businessMgtDao;
		}
		
		try {
			// throws DataAccessException
			this.haishinBusinessMgtDao.updateStatusRedoAsginTerminalFileAndRedoAsginTerminalByUnitName(
					statusValue, redoAsginTerminals,null, super.unit.getUnitName());
		} catch (DataAccessException e) {
			// ********************** Log **********************
			IgxLog.messageDetailsLog.error(this, e.getMessage());
			// ********************** Log **********************

			// ********************** Log **********************
			IgxLog.messageLog
			.error(
					this,
					"Update status and redo asgin terminals to db table '{}' for unit '{}' failed.",
					this.businessMgtDao.getTableName(),
					super.unit.getUnitName());
			// ********************** Log **********************

			throw e;
		}
	}
	
	@Override
	protected void executeIGXTypeSpecify()
							throws IGXTypeExecutionException {
		try {
			// ********************** Log **********************
			if (IgxLog.messageLog.isDebugMode()) {
				IgxLog.messageLog.debug(this, 
						"Building Asgmt action for haishin business '{}'.", super.unit
								.getUnitName());
			}
			// ********************** Log **********************
			
			// 執行指示檔內容產生
			// throws BuildAsgmtFileProcessException
			buildAsgmtAction();
			
			// ********************** Log **********************
			if (IgxLog.messageLog.isDebugMode()) {
				IgxLog.messageLog.debug(this, 
						"Building Asgmt action for haishin business '{}' completed.", super.unit
								.getUnitName());
			}
			// ********************** Log **********************
			
			// ********************** Log **********************
			if (IgxLog.messageLog.isDebugMode()) {
				IgxLog.messageLog.debug(this, 
						"Removing files for haishin business '{}'.", super.unit
								.getUnitName());
			}
			// ********************** Log **********************
			
			// 移除業務檔案(目標檔和確認檔）
			// throws UnitOperationException
			this.simpleBusinessUnitOperation.removeUnit(super.unit);
			
			// ********************** Log **********************
			if (IgxLog.messageLog.isDebugMode()) {
				IgxLog.messageLog.debug(this, 
						"Removing files for haishin business '{}' completed.", super.unit
								.getUnitName());
			}
			// ********************** Log **********************
		} catch (BuildAsgmtFileProcessException e) {
			throw new IGXTypeExecutionException(
					"Haishin business '" + business.getUnitName() +
					"' execution failed in building Asgmt file process", e);
		} catch (UnitOperationException e) {
			throw new IGXTypeExecutionException(
					"Haishin business '" + business.getUnitName() +
					"' execution failed in removing business file process", e);
		}
	}
	
	
	/*
	 * 執行指示內容產生，由最底層 class 實作。
	 */
	protected abstract void buildAsgmtAction()
							throws BuildAsgmtFileProcessException;
	
	
	// --- getter and setter ---
	
	
	public void setHaishinOutboxPathStr(String haishinOutboxPathStr) {
		this.haishinOutboxPathStr = haishinOutboxPathStr;
	}

	public void setSimpleBusinessUnitOperation(
			BusinessUnitOperation simpleBusinessUnitOperation) {
		this.simpleBusinessUnitOperation = simpleBusinessUnitOperation;
	}
}
